﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Media;
using System.Net;
using System.Threading;
using System.Xml.Serialization;
using VisaValeCheck.Library;

namespace VisaValeCheck
{
    public sealed class Visa
    {        
        #region Eventos
        public event EventHandler TudoBeleza;
        public event EventHandler ErroAoAtualizar;
        public event EventHandler NovoDeposito;
        public event EventHandler NovaCompra;
        public event EventHandler DataDoCreditoDefinida;
        public event EventHandler Carregando;        
        #endregion

        public VisaSaldo Saldo { get; private set; }

        private const string _c_urlConsulta = "http://www.cbss.com.br/inst/convivencia/SaldoExtrato.jsp?numeroCartao={0}&periodoSelecionado=4";

        private CookieContainer _cookieSession = new CookieContainer();
        private System.Windows.Threading.Dispatcher _dispatcher;
        private Thread _th = null;
        private NumeroCartao _numeroCartao;
        
        public Visa()
        {
            _dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;            
            CartaoManipulation.CarregarCartoes();
            NumeroCartao cartao = CartaoManipulation.UltimoCartaoSelecionado();
            if (cartao != null)
                this.Consulta(cartao);
        }

        private void ConsultaAssincrona()
        {
            try
            {
                while (Thread.CurrentThread.ThreadState == ThreadState.Running)
                {                    
                    this.ChamaEvento(Carregando);                    
                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(string.Format(_c_urlConsulta, _numeroCartao.Numero));
                    req.Headers[HttpRequestHeader.AcceptCharset] = "iso-8859-1";
                    req.CookieContainer = _cookieSession;
                    req.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
                    using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
                    {
                        using (Stream s = resp.GetResponseStream())
                        {
                            using (StreamReader sReader = new StreamReader(s, Encoding.GetEncoding("iso-8859-1")))
                            {
                                string paginaSaldo = System.Web.HttpUtility.HtmlDecode(sReader.ReadToEnd());
                                if (!this.CartaoValido(paginaSaldo))
                                    throw new Exception("Cartão inválido.");
                                lock (this)
                                {
                                    VisaSaldo sldNovo = new VisaSaldo(paginaSaldo, _numeroCartao);
                                    if (Saldo == null)
                                    {
                                        Saldo = sldNovo;
                                        SaldosSerialization.Salvar(sldNovo);
                                        CartaoManipulation.CarregarCartoes();
                                    }
                                    if (Saldo.AtualizarValores(sldNovo))
                                        this.ChamaEvento(DataDoCreditoDefinida);
                                    if (Saldo.AdicionarCompras(sldNovo))
                                        this.ChamaEvento(NovaCompra);
                                    if (Saldo.AdicionarCreditos(sldNovo))
                                        this.ChamaEvento(NovoDeposito);
                                    SaldosSerialization.Salvar();
                                }
                                #if DEBUG
                                using (FileStream f = File.Open("paginas.html", FileMode.Append))
                                {
                                    byte[] b = Encoding.UTF8.GetBytes("<hr />" + paginaSaldo);
                                    f.Write(b, 0, b.Length);
                                }
                                #endif
                            }
                        }
                    }
                    this.ChamaEvento(TudoBeleza);
                    //aguardar para atualizar
                    Thread.Sleep(3600000);
                }
            }
            catch (Exception ex)
            {
                if (!(ex is ThreadAbortException))
                {
                    this.ChamaEvento(ErroAoAtualizar);
                    Thread.CurrentThread.Abort();
                }
            }
        }

        private bool CartaoValido(string paginaSaldo)
        {
            return !Regex.Match(paginaSaldo, "Cartão inválido", RegexOptions.Singleline | RegexOptions.IgnoreCase).Success;
        }

        private delegate void Anonimous();
        public void Consulta(NumeroCartao numeroCartao)
        {
            _numeroCartao = numeroCartao;
            Saldo = SaldosSerialization.Carregar(numeroCartao);
            if (_th == null)
                _th = new Thread(new ThreadStart(this.ConsultaAssincrona));
            else
            {
                _th.Abort();
                _th = new Thread(new ThreadStart(this.ConsultaAssincrona));
            }
            _th.Start();
        }

        public void Sair()
        {
            if (_th != null)
            {
                _th.Abort();
                _th.Join();
            }
        }

        private void ChamaEvento(EventHandler evento)
        {
            if (evento != null)
            {
                Anonimous a = delegate() { evento(this, new EventArgs()); };
                _dispatcher.Invoke(a, null);
            }
        }
    }
}
